using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ShellAnywhere.Model
{
	using IParamToken = IToken<IParam>;
	using ParamToken = Token<IParam>;

	using IActionToken = IToken<IAction>;
	using ActionToken = Token<IAction>;

	using ParamTokenStream = Stream<IToken<IParam>>;
	using ActionTokenStream = Stream<IToken<IAction>>;

	public class Parser : StreamProcessor<IParamToken, IActionToken>
	{
		#region ctors
		public Parser(IActionMgr mgr, ParamTokenStream inputStream, ActionTokenStream outputStream, IVerb empty = null) : base(inputStream, outputStream) { _ActionMgr = mgr; _Empty = empty; }
		#endregion ctors

		#region properties
		public override ParamTokenStream InputStream { get; set; }
		public override ActionTokenStream OutputStream { get; set; }
		#endregion properties

		#region methods
		public override IActionToken NextOutputItem()
		{
			IActionToken token = default(ActionToken);

			token = Action();

			return token;
		}
		public IActionToken BuildActionToken(int index, IParamToken paramToken, IActionToken actionToken)
		{
			int dot = paramToken.Dot;
			List<IAction> actions = new List<IAction>();
			if (actionToken == null)
			{
				foreach (IParam child in paramToken.Children)
				{
					if (child is IVerb)
					{
						actions.Add(new Action(child as IVerb, null, null));
					}
					else if (child is ITarget)
					{
						actions.Add(new Action(_Empty, child as ITarget, null));
					}
					else
					{
						actions.Add(new Action(null, null, child));
					}
				}
			}
			else if (actionToken.Count == 1)
			{
				dot += actionToken.Dot;
				IVerb verb = actionToken.Child.Verb;
				if (actionToken.Child.Target == null)
				{
					foreach (IParam child in paramToken.Children)
					{
						if (child is ITarget)
						{
							actions.Add(new Action(verb, child as ITarget, null));
						}
					}
				}
				else
				{
					ITarget target = actionToken.Child.Target;
					IParam param = null;
					actions.Add(new Action(verb, target, param));
				}
			}
			else
				throw new Exception("wtf?");

			actionToken = new ActionToken(dot, actions.ToArray());

			return actionToken;
		}
		public IActionToken Action()
		{
			IActionToken actionToken = null;

			int index = 0;
			IParamToken pt = null;
			while ((pt = InputStream.NextItem()) != null )
			{
				actionToken = BuildActionToken(index++, pt, actionToken);
			}

			return actionToken;
		}
		#endregion methods

		#region fields
		private IVerb _Empty;
		private IActionMgr _ActionMgr;
		#endregion fields
	}
}
